#####################################################################
# File:         DependantsManager.py
# Product:      KnowledgeEngine
#
# Copyright:    Copyright (c) 2002, Faulkner Ltd.
# Author:       Brian Oliver
#
# Description:  This file defines the DependantsManager class/interface,
#               mix-in which provides support for managing the dependants
#               of a Knowledge Engine Component.
#
#               More specifically, this mix-in manages a collection
#               of references to Components that are required for
#               the successful operation of the component that inherits
#               this class.
#
# Concepts:     This class introduces the concepts of "Purpose" and
#               "Scope" of dependants.
#
#               The "Purpose" (a string) is used to identify why a
#               particular dependant is being tracked,
#               eg: showif, reporting, etc.
#
#               The "Scope" (also a string) is used to track the
#               'area' in which the dependant component is used.
#               eg: Model identity.  
#
#               In most circumstances, "Scope" isn't used, including in "showif"
#
# Note:         Both Purpose and Scope are case sentitive.  
#
# See Also:     Component
#####################################################################

#####################################################################
## KnowledgeEngine Library Imports
from Common import *

#####################################################################
## Zope Library Imports
# (none)
 
#####################################################################
## Python Library Imports
# (none)

#####################################################################
## DependantsManager Class Definition
class DependantsManager:
    """
        A class to manage the dependants of a component
        (the components that require a component)
    """

    #---------------------------------------------------------------#
    # The default purpose and scope
    DEFAULT_PURPOSE = "unknown"
    DEFAULT_SCOPE = "all"
        
    #---------------------------------------------------------------#

    def establishDependantsDictionary(self):
        """
            Establish the dependants dictionary (if needed)
        """
        
        #do we have dependants?
        try:
            dumby = len(self.dependantsDictionary)
        except:        
            self.dependantsDictionary = {}
            self._p_changed = 1  #signal mutable object change for Zope                 
                
    #---------------------------------------------------------------#

    def clearDependantsDictionary(self):
        """
            Empty the contents of the dependants dictionary
        """
        
        self.establishDependantsDictionary()
        self.dependantsDictionary = {}
        self._p_changed = 1  #signal mutable object change for Zope
                
    #---------------------------------------------------------------#

    def hasDependants(self, purpose = None, scope = None):
        """
            Return if dependants are registered for the specified
            purpose in the specified scope
        """

        #determine the default purpose and scope (if not supplied)
        if purpose == None:
            purpose = self.DEFAULT_PURPOSE
        if scope == None:
            scope = self.DEFAULT_SCOPE

        #make sure we have a dependants dictionary
        self.establishDependantsDictionary()
        
        #does the purpose exist?
        if self.dependantsDictionary.has_key(purpose):

            #does the scope exist?
            if self.dependantsDictionary[purpose].has_key(scope):
                
                return len(self.dependantsDictionary[purpose][scope]) > 0
            else:
                return false
        else:
            return false

    #---------------------------------------------------------------#

    def addDependant(self, identity, component, purpose = None, scope = None):
        """
            Add the specified component as a dependant with the
            specified identity, purpose and scope.
        """

        #determine the default purpose and scope (if not supplied)
        if purpose == None:
            purpose = self.DEFAULT_PURPOSE
        if scope == None:
            scope = self.DEFAULT_SCOPE

        #make sure we have a dependants dictionary
        self.establishDependantsDictionary()

        #does the purpose exist?
        if self.dependantsDictionary.has_key(purpose):

            #does the scope exist?
            if self.dependantsDictionary[purpose].has_key(scope):

                #add the identity -> component mapping
                self.dependantsDictionary[purpose][scope][identity] = component
                
                self._p_changed = 1  #signal mutable object change for Zope
            else:
                #add the scope and identity -> component mapping
                self.dependantsDictionary[purpose][scope] = {identity:component}
                
                self._p_changed = 1  #signal mutable object change for Zope
        else:
            #add the purpose, scope and identity -> component mapping
            self.dependantsDictionary[purpose] = {scope:{identity:component}}
            
            self._p_changed = 1  #signal mutable object change for Zope
        
        ###print "DEBUG: DependantsManager.addDependant() Added %s as dependant of %s with purpose %s (%d)" % (component.getTitle(), self.getTitle(), purpose, len(self.dependantsDictionary[purpose][scope]))
    
    #---------------------------------------------------------------#

    def removeDependant(self, identity, purpose = None, scope = None):
        """
            Remove the specified component as a dependant with the
            specified identity, purpose and scope.
        """

        #determine the default purpose and scope (if not supplied)
        if purpose == None:
            purpose = self.DEFAULT_PURPOSE
        if scope == None:
            scope = self.DEFAULT_SCOPE

        #make sure we have a dependants dictionary
        self.establishDependantsDictionary()
            
        #does the purpose exist?
        if self.dependantsDictionary.has_key(purpose):

           #does the scope exist?
           if self.dependantsDictionary[purpose].has_key(scope):

                #remove the identity -> component mapping
                del self.dependantsDictionary[purpose][scope][identity]
                
                self._p_changed = 1  #signal mutable object change for Zope
            
    #---------------------------------------------------------------#

    def getDependants(self, purpose = None, scope = None):

        """
            Return a dictionary of dependants with the specified
            purpose and scope
        """

        #determine the default purpose and scope (if not supplied)
        if purpose == None:
            purpose = self.DEFAULT_PURPOSE
        if scope == None:
            scope = self.DEFAULT_SCOPE

        #make sure we have a dependants dictionary
        self.establishDependantsDictionary()

        #does the purpose exist?
        if self.dependantsDictionary.has_key(purpose):

            #does the scope exist?
            if self.dependantsDictionary[purpose].has_key(scope):

                #return the identity -> component mappings
                return self.dependantsDictionary[purpose][scope]
            else:
                return {}
        else:
            return {}
        
    #---------------------------------------------------------------#

#####################################################################
## Class Initialisation
# (none)
